package com.bingbing.back.service.Impl;

import com.bingbing.back.dto.CityLocDto;
import com.bingbing.back.dto.SchoolInfoDto;
import com.bingbing.back.mapper.CityLocMapper;
import com.bingbing.back.mapper.SchoolAdmScoreMapper;
import com.bingbing.back.mapper.SchoolInfoMapper;
import com.bingbing.back.myUtils.MySort;
import com.bingbing.back.po.CityLoc;
import com.bingbing.back.po.SchoolAdmScore;
import com.bingbing.back.po.SchoolInfo;
import com.bingbing.back.service.SchoolInfoService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

import static java.lang.Math.min;

@Service
public class SchoolInfoServiceImpl implements SchoolInfoService {
    @Resource
    private SchoolInfoMapper schoolInfoMapper;
    @Resource
    private CityLocMapper cityLocMapper;
    @Resource
    private MySort mySort;
    @Resource
    private SchoolAdmScoreMapper schoolAdmScoreMapper;

    @Resource
    private SqlSessionFactory sqlSessionFactory;
    private static Map<Integer, Integer> haveId = new HashMap<>();
    private static int batchUpdateSize = 200;

    @Override
    public List<SchoolInfo> recommendSchool(SchoolInfoDto dto) {
        //前端只显示前20个推荐高校
        int showListNum = 20;
        Random random = new Random();

        List<SchoolInfo> result = new ArrayList<>();
        List<SchoolInfo> list = schoolInfoMapper.recommendSchool();
        for (int i = 0; i < showListNum; i++) {
            addClout(list.get(i).getSchoolId(), 1);
            result.add(list.get(i));
        }
        int cnt = 0;
        for (int i = showListNum; i < min(1000, list.size()); i++) {
            SchoolInfo s = list.get(i);
            String City = s.getSchoolCity();
            String Pro = s.getSchoolProvince();

            if(City.contains(dto.getUserCity()) || Pro.contains(dto.getUserProvince())){
                if(++cnt > showListNum / 2) break;
                int x = random.nextInt(showListNum);
                if(list.get(x).getSchoolProvince().contains(dto.getUserProvince())) continue;
                result.add(x, s);
            }
        }
        return result;
    }

    @Override
    public PageInfo<SchoolInfoDto> searchSchool(int pageNum, int pageSize, SchoolInfoDto dto) {
        PageInfo<SchoolInfoDto> page = null;
        PageHelper.startPage(pageNum, pageSize);
        List<SchoolInfoDto> list = schoolInfoMapper.searchSchool(dto);
        //将逗号分割改为|竖线分割
        list.forEach(s->{
            addClout(s.getSchoolId(), 3);
            s.setSchoolType(String.join(" | ", s.getSchoolType().split(",")));
            s.setDoType(String.join(" | ", s.getDoType().split(",")));
            s.setFeature(String.join(" | ", s.getFeature().split(",")));
            s.setScoreAndRank("-");
        });
        if(dto.getUseScoreSearch() == 1) {
            list.forEach(s->{
                String str = "";
                if(s.getSchoolLoScore() != null) str += s.getSchoolLoScore().toString();
                else str += "-";
                str += "/";
                if(s.getSchoolLoRank() != null) str += s.getSchoolLoRank().toString();
                else str += "-";
                s.setScoreAndRank(str);
            });
        }

        page = new PageInfo<>(list, 10);
        // 如果dto中Closer==1则需要按照距离排序
        if(dto.getCloser() == 1) {
            CityLoc cityLoc = cityLocMapper.getPos(dto.getUserProvince(), dto.getUserCity());
            list = mySort.sortByDistance(cityLoc.getLongitude(), cityLoc.getLatitude(), list);
            page.setList(list);
        }
        return page;
    }

    @Override
    public void addClout(int schoolId, int val) {
        haveId.put(schoolId, haveId.getOrDefault(schoolId, 0) + val);
        if(haveId.size() >= batchUpdateSize) {
            SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
            try {
                SchoolInfoMapper Mapper = sqlSession.getMapper(SchoolInfoMapper.class);
                Mapper.addClout(haveId);
                sqlSession.commit();
                haveId.clear();
            } catch (Exception e){
                System.out.println(e);
                sqlSession.rollback();
            } finally {
                if(sqlSession != null){
                    sqlSession.close();
                }
            }
        }
    }

    @Override
    public SchoolInfoDto showSchoolById(int schoolId) {
        addClout(schoolId, 40);
        return schoolInfoMapper.showSchoolById(schoolId);
    }

    @Override
    public List<String> searchIntroBySchoolId(int schoolId) {
        addClout(schoolId, 10);
        List<String> list = new ArrayList<>();
        String intro = schoolInfoMapper.searchIntroBySchoolId(schoolId);
        String[] result = intro.split("\\\\n");
        for(int i = 0; i < result.length; i++){
            list.add(result[i]);
        }
        return list;
    }

    @Override
    public List<SchoolInfoDto> getCloseScoreSchool(int schoolId) {
        List<SchoolInfoDto> result = new ArrayList<>();
        SchoolAdmScore sAS = schoolAdmScoreMapper.getLatestYear(schoolId);
        List<SchoolAdmScore> list = schoolAdmScoreMapper.getCloseScoreSchool(schoolId, sAS.getAdmYear(), sAS.getSchoolLoScore());
        list.forEach(s->{
            addClout(s.getSchoolId(), 8);
            SchoolInfoDto dto = schoolInfoMapper.showSchoolById(s.getSchoolId());
            dto.setSchoolLoScore(s.getSchoolLoScore());
            result.add(dto);
        });
        return result;
    }

    @Override
    public List<CityLocDto> findByProvince() {
        List<CityLoc> list = cityLocMapper.showAllProvince();
        List<CityLocDto> result = new ArrayList<>();

        list.forEach(s->{
            CityLocDto dto = new CityLocDto(s);
            dto.setSchools(schoolInfoMapper.findByProvince(s.getProvince()));
            result.add(dto);
        });
        return result;
    }
}